﻿#pragma once
#include "CubeTexture.h"
#include "Material.h"
#include "Path.h"
#include "ShaderProgram.h"


class FCubeTexture;

class FEnvironmentMappingMaterial final
	: public FMaterial
{
public:

	enum EType
	{
		// 反射
		Reflact,

		// 折射
		Refract,
	};

private:

	std::shared_ptr<FCubeTexture> CubeTexture;



	EType EnvironType = EType::Reflact;

public:



	void SetEnvType(const EType EnvType)
	{
		EnvironType = EnvType;
	}

	virtual bool Init() override
	{
		if (!FMaterial::Init())
		{
			return false;
		}

		Shader->SetLightingModel(ELightingModel::None);

		CubeTexture = std::make_shared<FCubeTexture>();

		CubeTexture->LoadFromFile(
			{
				FPath::BuildImgPath("SkyCube/right.jpg"),
				FPath::BuildImgPath("SkyCube/left.jpg"),
				FPath::BuildImgPath("SkyCube/top.jpg"),
				FPath::BuildImgPath("SkyCube/bottom.jpg"),
				FPath::BuildImgPath("SkyCube/front.jpg"),
				FPath::BuildImgPath("SkyCube/back.jpg"),
		
			});

		Shader->Use();

		Shader->SetInt("skybox", 0);

		return true;
	}

	virtual void Use() override
	{
		FMaterial::Use();

		CubeTexture->BindTextureUnit(0);

		Shader->SetBool("isReflect", EnvironType == EType::Reflact);

	}

	const std::string& GetFsSrcCode() const override  // NOLINT(modernize-use-nodiscard)
	{
		static std::string CodeStr = R"(

			#version 410 core
			out vec4 FragColor;
			
			in VS_OUT
			{
				vec3 Normal;
				vec3 Position;
			} fs_in;

			uniform samplerCube skybox;
			uniform vec3 cameraPos;
			uniform bool isReflect;

			void main()
			{
				vec3 viewVec = normalize(fs_in.Position - cameraPos);

				if(isReflect)
				{
					vec3 reflectVec = reflect(viewVec, normalize(fs_in.Normal));
					FragColor = vec4(texture(skybox, reflectVec).rgb, 1.0f);
				}
				else
				{
					float ratio = 1.00 / 1.52;
					vec3 refractVec = refract(viewVec, normalize(fs_in.Normal), ratio);
					FragColor = vec4(texture(skybox, refractVec).rgb, 1.0f);
					//FragColor = vec4(refractVec, 1.0f);
				}

			}
		)";


		return CodeStr;
	}

	const std::string& GetVsSrcCode() const override  // NOLINT(modernize-use-nodiscard)
	{
		static std::string CodeStr = R"(

			#version 410 core 
			
			layout (location = 0) in vec3 aPos;
			layout (location = 1) in vec3 aNormal;

			out VS_OUT
			{
				vec3 Normal;
				vec3 Position;
			} vs_out;

			uniform mat4 projection;
			uniform mat4 view;
			uniform mat4 model;
			
			void main()
			{
			    gl_Position =  projection * view * model *vec4(aPos.x, aPos.y, aPos.z , 1.0);

				// 法线变换矩阵   https://zhuanlan.zhihu.com/p/72734738
				// 因为顶点进行 缩放时 导致 原先的法线并不会时 缩放后的顶点真正的法线，方向将不会在 垂直
				vs_out.Normal = mat3(transpose(inverse(model))) * aNormal;

				vs_out.Position = vec3(model * vec4(aPos, 1.0));
			}

		)";

		return CodeStr;
	}
};